package weka.numerial.optimization;

import java.applet.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.io.*;
public class MySvm_toy extends Applet
{
	/**
	 * 
	 * 
	 * 
	 */  
	private static final long serialVersionUID = 1L;
	static final String DEFAULT_PARAM = "-t 2 -c 100";
	int XLEN;
	int YLEN;

	// off-screen buffer

	Image buffer;
	Graphics buffer_gc;

	// pre-allocated colors

	final static Color colors[] =
	{ new Color(0, 50, 0), new Color(90, 10, 120), new Color(79, 20, 10),
			new Color(20, 100, 120), new Color(100, 20, 200),
			new Color(100, 200, 50), new Color(60, 100, 60) };

	class point
	{
		point(double x, double y, byte value)
		{
			this.x = x;
			this.y = y;
			this.value = value;
		}

		double x, y;
		byte value;
	}

	Vector<point> point_list = new Vector<point>();
	byte current_value = 1;

	public void init()
	{
		setSize(getSize());

		final Button button_change = new Button("Change");
		Button button_run = new Button("Run");
		Button button_clear = new Button("Clear");
		Button button_save = new Button("Save");
		Button button_load = new Button("Load");
		final TextField input_line = new TextField(DEFAULT_PARAM);

		BorderLayout layout = new BorderLayout();
		this.setLayout(layout);

		Panel p = new Panel();
		GridBagLayout gridbag = new GridBagLayout();
		p.setLayout(gridbag);

		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 1;
		c.gridwidth = 1;
		gridbag.setConstraints(button_change, c);
		gridbag.setConstraints(button_run, c);
		gridbag.setConstraints(button_clear, c);
		gridbag.setConstraints(button_save, c);
		gridbag.setConstraints(button_load, c);
		c.weightx = 5;
		c.gridwidth = 5;
		gridbag.setConstraints(input_line, c);

		button_change.setBackground(colors[current_value]);

		p.add(button_change);
		p.add(button_run);
		p.add(button_clear);
		p.add(button_save);
		p.add(button_load);
		p.add(input_line);
		this.add(p, BorderLayout.SOUTH);

		button_change.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_change_clicked();
				button_change.setBackground(colors[current_value]);
			}
		});

		button_run.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_run_clicked(input_line.getText());
			}
		});

		button_clear.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_clear_clicked();
			}
		});

		button_save.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_save_clicked();
			}
		});

		button_load.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_load_clicked();
			}
		});

		input_line.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				button_run_clicked(input_line.getText());
			}
		});

		this.enableEvents(AWTEvent.MOUSE_EVENT_MASK);
	}

	void draw_point(point p)
	{
		Color c = colors[p.value + 3];

		Graphics window_gc = getGraphics();
		buffer_gc.setColor(c);
		buffer_gc.fillRect((int) (p.x * XLEN), (int) (p.y * YLEN), 4, 4);
		window_gc.setColor(c);
		window_gc.fillRect((int) (p.x * XLEN), (int) (p.y * YLEN), 4, 4);
	}

	void clear_all()
	{
		point_list.removeAllElements();
		if (buffer != null)
		{
			buffer_gc.setColor(colors[0]);
			buffer_gc.fillRect(0, 0, XLEN, YLEN);
		}
		repaint();
	}

	void draw_all_points()
	{
		int n = point_list.size();
		for (int i = 0; i < n; i++)
			draw_point(point_list.elementAt(i));
	}

	void button_change_clicked()
	{
		++current_value;
		if (current_value > 3)
			current_value = 1;
	}

	private static double atof(String s)
	{
		return Double.valueOf(s).doubleValue();
	}

	private static int atoi(String s)
	{
		return Integer.parseInt(s);
	}

	void button_run_clicked(String args)
	{
		double c=0;
		// parse options
		StringTokenizer st = new StringTokenizer(args);
		String[] argv = new String[st.countTokens()];
		for(int i=0;i<argv.length;i++)
			argv[i] = st.nextToken();

		for(int i=0;i<argv.length;i++)
		{
			if(argv[i].charAt(0) != '-') break;
			if(++i>=argv.length)
			{
				System.err.print("unknown option\n");
				break;
			}
			switch(argv[i-1].charAt(1))
			{
				
				case 'c':
					c = atof(argv[i]);
					break;
				
			}
		}
		
		
		
		
		// guard
		if (point_list.isEmpty())
			return;

		double x[][] = new double[point_list.size()][2];
		double y[] = new double[point_list.size()];
		// //double a[] = new double[3];
		// /AbstractLogistcRegression l = null;
		for (int i = 0; i < point_list.size(); i++)
		{
			System.out.print(point_list.get(i).x + "-");
			System.out.print(point_list.get(i).y + "-");
			System.out.println("target value:"+point_list.get(i).value);

			x[i][0] = point_list.get(i).x;
			x[i][1] = point_list.get(i).y;

			y[i] = point_list.get(i).value;

		}
		MySVM m = new MySVM(x, y, c, 1e-4, 1e-8);
		m.run();
		

		Graphics window_gc = getGraphics();
		double[] instance = new double[2];
		for (int i = 0; i < XLEN; i++)
		{
			for (int j = 0; j < YLEN; j++)
			{
				instance[0] = (double) i / XLEN;
				instance[1] = (double) j / YLEN;

				double d = m.svmOutput(instance, m.getW(), m.getB());
				if (d >= 0)
				{
					d = 0;
				}
				else
				{
					d = 3;
				}
				buffer_gc.setColor(colors[(int) d]);
				window_gc.setColor(colors[(int) d]);
				buffer_gc.drawLine(i, j, i, j);
				window_gc.drawLine(i, j, i, j);
			}
		}

		draw_all_points();
	}

	void button_clear_clicked()
	{
		clear_all();
	}

	void button_save_clicked()
	{
		FileDialog dialog = new FileDialog(new Frame(), "Save", FileDialog.SAVE);
		dialog.setVisible(true);
		String filename = dialog.getDirectory() + dialog.getFile();
		if (filename == null)
			return;
		try
		{
			DataOutputStream fp = new DataOutputStream(
					new BufferedOutputStream(new FileOutputStream(filename)));
			int n = point_list.size();
			for (int i = 0; i < n; i++)
			{
				point p = point_list.elementAt(i);
				fp.writeBytes(p.value + " 1:" + p.x + " 2:" + p.y + "\n");
			}
			fp.close();
		}
		catch (IOException e)
		{
			System.err.print(e);
		}
	}

	void button_load_clicked()
	{
		FileDialog dialog = new FileDialog(new Frame(), "Load", FileDialog.LOAD);
		dialog.setVisible(true);
		String filename = dialog.getDirectory() + dialog.getFile();
		if (filename == null)
			return;
		clear_all();
		try
		{
			BufferedReader fp = new BufferedReader(new FileReader(filename));
			String line;
			while ((line = fp.readLine()) != null)
			{
				StringTokenizer st = new StringTokenizer(line, " \t\n\r\f:");
				byte value = (byte) atoi(st.nextToken());
				st.nextToken();
				double x = atof(st.nextToken());
				st.nextToken();
				double y = atof(st.nextToken());
				point_list.addElement(new point(x, y, value));
			}
			fp.close();
		}
		catch (IOException e)
		{
			System.err.print(e);
		}
		draw_all_points();
	}

	protected void processMouseEvent(MouseEvent e)
	{
		if (e.getID() == MouseEvent.MOUSE_PRESSED)
		{
			if (e.getX() >= XLEN || e.getY() >= YLEN)
				return;
			double value = 0;
			if (current_value % 2 == 0)
			{
				value = 1;
			}
			else
			{
				value = -1;
			}
			point p = new point((double) e.getX() / XLEN, (double) e.getY()
					/ YLEN, (byte) value);
			point_list.addElement(p);
			draw_point(p);
			
		}
	}

	public void paint(Graphics g)
	{
		// create buffer first time
		if (buffer == null)
		{
			buffer = this.createImage(XLEN, YLEN);
			buffer_gc = buffer.getGraphics();
			buffer_gc.setColor(colors[0]);
			buffer_gc.fillRect(0, 0, XLEN, YLEN);
		}
		g.drawImage(buffer, 0, 0, this);
	}

	public Dimension getPreferredSize()
	{
		return new Dimension(XLEN, YLEN + 50);
	}

	public void setSize(Dimension d)
	{
		setSize(d.width, d.height);
	}

	public void setSize(int w, int h)
	{
		super.setSize(w, h);
		XLEN = w;
		YLEN = h - 50;
		clear_all();
	}

	public static void main(String[] argv)
	{
		new AppletFrame1("svm_toy", new MySvm_toy(), 500, 500 + 50);
	}
}

class AppletFrame1 extends Frame
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	AppletFrame1(String title, Applet applet, int width, int height)
	{
		super(title);
		this.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});
		applet.init();
		applet.setSize(width, height);
		applet.start();
		this.add(applet);
		this.pack();
		this.setVisible(true);
	}
}
